package com.credithc.fastdfs.api.util;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.EntityBuilder;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.client.cache.CacheConfig;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.credithc.fastdfs.api.config.HttpClientConfig;
import com.credithc.fastdfs.api.config.SystemConfig;
import com.credithc.fastdfs.api.exception.ResourceNotFoundException;
import com.credithc.fastdfs.util.FastdfsUtil;
import com.credithc.fastdfs.util.PathUtil;

public class HttpClientProxy {
	private static Logger log = LoggerFactory.getLogger(HttpClientProxy.class);
	private static class SingletonHolder {
		static final HttpClientProxy instance = new HttpClientProxy();
	}

	public static HttpClientProxy getInstance() {
		return SingletonHolder.instance;
	}


	private static CloseableHttpClient httpClient;

	static {
		PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
		cm.setMaxTotal(HttpClientConfig.MAX_TOTAL_CONNECTIONS);
		cm.setDefaultMaxPerRoute(HttpClientConfig.MAX_ROUTE_CONNECTIONS);
		
		
		RequestConfig requestConfig = RequestConfig.custom()
				.setSocketTimeout(HttpClientConfig.CONNECT_TIMEOUT)
		        .setConnectTimeout(HttpClientConfig.CONNECT_TIMEOUT)
		        .build();
		//缓存
		/*		
 		CacheConfig cacheConfig = CacheConfig.custom()
	            .setMaxCacheEntries(1000)
	            .setMaxObjectSize(8192)
	            .build();
	    */
		httpClient = HttpClients.custom()
				.setDefaultRequestConfig(requestConfig)
				.setConnectionManager(cm)
				.build();
	}

	public static HttpClient getHttpClient() {
		return httpClient;
	}
	
	/**
	 * MAP类型数组转换成HttpEntity类型
	 * 
	 */
	public static HttpEntity transMap2HttpEntity(Map<String, String> params) {
		List<NameValuePair> nvps = new ArrayList<NameValuePair>();
		if (params != null) {
			for (Map.Entry<String, String> entry : params.entrySet()) {
				nvps.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
			}
		}
		
		EntityBuilder builder = EntityBuilder.create();
		builder.setParameters(nvps);
		HttpEntity httpEntity=builder.build();

		return httpEntity;
	}
	

	/**
	 * 发送HTTP的POST请求
	 * 
	 * @param requestUrl
	 *            请求URL地址
	 * @param requestContent
	 *            请求内容
	 * @return String 响应内容
	 * @throws IOException
	 */
	public static String post(String requestUrl, String requestContent) throws IOException {
		StringEntity requestEntity = new StringEntity(requestContent);
		return post(requestUrl,requestEntity);
	}

	/**
	 * 
	 * <br>描 述：
	 * <br>作 者：zj
	 * <br>历 史: (版本) 作者 时间 注释
	 * @param requestUrl
	 * @param params
	 * @return
	 * @throws IOException
	 */
	public static String post(String requestUrl, Map<String, String> params) throws IOException {
		return post(requestUrl,transMap2HttpEntity(params));
	}
	
	/**
	 * 
	 * <br>描 述：
	 * <br>作 者：zj
	 * <br>历 史: (版本) 作者 时间 注释
	 * @param requestUrl
	 * @param httpEntity
	 * @return
	 * @throws IOException
	 */
	public static String post(String requestUrl, HttpEntity httpEntity) throws IOException {
		String result = null;
		HttpPost httpPost = new HttpPost(requestUrl);
		httpPost.setEntity(httpEntity);
		try {
			CloseableHttpResponse httpResponse = httpClient.execute(httpPost);
			try {
				HttpEntity entity = httpResponse.getEntity();
				if (httpResponse.getStatusLine().getReasonPhrase().equals("OK") && httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
					result = EntityUtils.toString(entity, "UTF-8");
				}
				EntityUtils.consume(entity);
			} finally {
				if (null != httpResponse) {
					httpResponse.close();
				}
			}
		} finally {
			if (null != httpPost) {
				httpPost.releaseConnection();
			}
		}
		return result;
	}
	
	/**
	 * 下载文件
	 * @throws IOException
	 * @throws ResourceNotFoundException 
	 */
	public static void handleDownload(String url,HttpServletRequest request, HttpServletResponse response,String orgFileName,String openType) throws ClientProtocolException, IOException, ResourceNotFoundException {
		//1.直接跳转到相应的url
//		response.sendRedirect(url);
		//2.采用http代理下载
	    HttpGet httpGet =new HttpGet(url);
	    try {
	    	CloseableHttpResponse httpResponse = httpClient.execute(httpGet);
	    	try{
	    		int statusCode=httpResponse.getStatusLine().getStatusCode();
	    		if(statusCode== HttpStatus.SC_OK){
	    			log.info("httpClient直接读取:"+url);
				    HttpEntity entity = httpResponse.getEntity();
				    InputStream httpClientInputStream = entity.getContent();
					BufferedInputStream bis = null;
					BufferedOutputStream bos = null;
					String userAgent = request.getHeader("User-Agent");
					UserAgentUtil.setHeaders( response,userAgent,orgFileName,entity.getContentLength(),openType);
					bis = new BufferedInputStream(httpClientInputStream);
					bos = new BufferedOutputStream(response.getOutputStream());
					byte[] buff = new byte[2048];
					int bytesRead;
					while (-1 != (bytesRead = httpClientInputStream.read(buff, 0, buff.length))) {
						bos.write(buff, 0, bytesRead);
					}
					//EntityUtils.consume(entity);
					httpClientInputStream.close();
					bis.close();
					bos.close();
	    		}else{
	    			log.info("Fastdfs-api文件读取:"+url);
	    			String fileId=StringUtils.remove(url, SystemConfig.FILE_SYSTEM_URL);
	    			String tmpFilePath=PathUtil.getRootPath()+String.valueOf(File.separatorChar)+UUID.randomUUID().toString().replaceAll("-", "");
	    			log.info(String.format("fileId:%s,tmpFilePath:%s", fileId,tmpFilePath));
	    			
	    			int success=FastdfsUtil.getInstance().downloadFile(fileId, tmpFilePath);
	    			
	    			if(success==0){
	    				File file=new File(tmpFilePath);
					    InputStream fileInputStream = new FileInputStream(new File(tmpFilePath));
						BufferedInputStream bis = null;
						BufferedOutputStream bos = null;
						
						String userAgent = request.getHeader("User-Agent");
						UserAgentUtil.setHeaders( response,userAgent,orgFileName,file.length(),openType);
						
						bis = new BufferedInputStream(fileInputStream);
						bos = new BufferedOutputStream(response.getOutputStream());
						byte[] buff = new byte[1024];
						int bytesRead;
						while (-1 != (bytesRead = bis.read(buff, 0, buff.length))) {
							bos.write(buff, 0, bytesRead);
						}
						bis.close();
						bos.close();
						file.delete();
	    			}else{
		    			log.error(String.format("resource not found,url:%s,statusCode:%s", url,statusCode));
		    			/*response.setStatus(statusCode);*/
		    			//抛出异常，后台捕获，返回给调用系统
		    			throw new ResourceNotFoundException("resource not found");
	    			}
	    		}
			} finally {
				if (null != httpResponse) {
					httpResponse.close();
				}
			}
	    } finally {
			if (null != httpGet) {
				httpGet.releaseConnection();
			}
		}
	}
	
	
}
